package com.tnxst.phexamination.room.repository;

import android.content.Context;
import android.os.AsyncTask;

import com.tnxst.phexamination.room.dao.BaseDao;
import com.tnxst.phexamination.room.dao.ServicePackageDao;
import com.tnxst.phexamination.room.database.PhexaminationDatabase;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * @param <E> entity
 */
public abstract class RoomRepository<E, D extends BaseDao<E>> {

    private PhexaminationDatabase database;

    private D dao;

    public RoomRepository(Context context, String account) {
        database = PhexaminationDatabase.getDatabase(context,account);
        setDao();
    }

    private void setDao(){
        try {
            Method method = PhexaminationDatabase.class.getDeclaredMethod("get" + getName(), new Class<?>[]{});
            if (method == null){
                return;
            }
            dao = (D) method.invoke(database,new Object[]{});
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void insert(E... e) {
        new InsertAsyncTask(dao).execute(e);
    }

    public void update(E... e) {
        new UpdateAsyncTask(dao).execute(e);
    }

    public void delete(E... e) {
        new DeleteAsyncTask(dao).execute(e);
    }

    public E findById(Integer id) {
        AsyncTask<Integer, Void, E> execute = new FindByIdAsyncTask(dao).execute(id);
        try {
            return execute.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<E> findAll() {
        AsyncTask<Void, Void, List<E>> execute = new FindAllAsyncTask(dao).execute();

        try {
            return execute.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public E findByMap(LinkedHashMap map){
        AsyncTask<LinkedHashMap, Void, E> execute = new FindByMapAsyncTask(dao).execute(map);
        try {
            return execute.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<E> findByLike(String field, Object o) {
        AsyncTask<Object, Void, List<E>> execute = new FindByLikeAsyncTask(dao).execute(field,o);
        try {
            return execute.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<E> findByLikeAndWhere(String field, Object o, String key, Object value) {
        AsyncTask<Object, Void, List<E>> execute = new FindByLikeAndWhereAsyncTask(dao).execute(field,o,key,value);
        try {
            return execute.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public E findByField(String field, Object value){
        AsyncTask<Object, Void, E> execute = new FindByFieldAsyncTask(dao).execute(field,value);
        try {
            return execute.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<E> findByFieldList(String field, Object value){
        AsyncTask<Object, Void, List<E>> execute = new FindByFieldListAsyncTask(dao).execute(field,value);
        try {
            return execute.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    class UpdateAsyncTask extends AsyncTask<E, Void, Void> {
        private BaseDao dao;

        public UpdateAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected Void doInBackground(E... e) {
            dao.update(e);
            return null;
        }
    }

    class DeleteAsyncTask extends AsyncTask<E, Void, Void> {
        private BaseDao dao;

        public DeleteAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected Void doInBackground(E... e) {
            dao.delete(e);
            return null;
        }
    }

    class FindAllAsyncTask extends AsyncTask<Void, Void, List<E>> {
        private BaseDao dao;

        public FindAllAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected List<E> doInBackground(Void... voids) {
            return dao.findAll();
        }
    }


    class InsertAsyncTask extends AsyncTask<E, Void, Void> {
        private BaseDao dao;

        public InsertAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected Void doInBackground(E... e) {
            dao.insert(e);
            return null;
        }
    }

    class FindByIdAsyncTask extends AsyncTask<Integer, Void, E> {
        private BaseDao dao;

        public FindByIdAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected E doInBackground(Integer... ids) {
            return (E) dao.findById(ids[0]);
        }
    }

    class FindByFieldAsyncTask extends AsyncTask<Object, Void, E> {
        private BaseDao dao;

        public FindByFieldAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected E doInBackground(Object... ids) {
            return (E) dao.findByField(ids[0].toString(),ids[1]);
        }
    }

    class FindByFieldListAsyncTask extends AsyncTask<Object, Void, List<E>> {
        private BaseDao dao;

        public FindByFieldListAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected List<E> doInBackground(Object... ids) {
            return dao.findByFieldList(ids[0].toString(),ids[1]);
        }
    }

    class FindByLikeAsyncTask extends AsyncTask<Object, Void, List<E>> {
        private BaseDao dao;

        public FindByLikeAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected List<E> doInBackground(Object... ids) {
            return dao.findByLike(ids[0].toString(),ids[1]);
        }
    }

    class FindByLikeAndWhereAsyncTask extends AsyncTask<Object, Void, List<E>> {
        private BaseDao dao;

        public FindByLikeAndWhereAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected List<E> doInBackground(Object... ids) {
            return dao.findByLikeAndWhere(ids[0].toString(),ids[1],ids[2].toString(),ids[3]);
        }
    }

    class FindByMapAsyncTask extends AsyncTask<LinkedHashMap, Void, E> {
        private BaseDao dao;

        public FindByMapAsyncTask(BaseDao dao) {
            this.dao = dao;
        }

        @Override
        protected E doInBackground(LinkedHashMap... maps) {
            return (E) dao.findByMap(maps[0]);
        }
    }


    private String getName(){
        Class<?> clazz = (Class<?>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        String tableName = clazz.getSimpleName();
        return tableName;
    }




}
